package com.owen.he.jee.utils.excel;

import java.io.File;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Serializable;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;


/***
 *  XML文件工具类，支持通过XPATH来操作
 *  <p> XPATH的使用，假设现在有一个节点格式如果下:
 *  <p><root>root_value
 *  <p>		<element name="e1">e1_value</element>
 *  <p>		<element name="e2">e2_value</element>
 *  <p></root>
 *  <p>例1：取root节点，XPATH为/root
 *  <p>例2：取所有element，XPATH为/root/element
 *  <p>例3：取name为e1的element节点，XPATH为/root/elelment[@name='e1']
 * @author Fish
 * @version 1.0
 */
public class XmlDao implements Serializable{
	// Xml文档
	private Document doc = null;

	/**
	 * 构造函数，传入文件，建立Xml文档
	 * 
	 * @param file
	 * @throws DocumentException
	 */
	public XmlDao(File file) throws Exception {
		SAXReader reader = new SAXReader();
		reader.setValidation(false);
		reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);  
		this.doc = reader.read(file);
	}
	
	public XmlDao(Reader reader) throws Exception {
		SAXReader read = new SAXReader();
		read.setValidation(false);
		read.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);  
		this.doc = read.read(reader);
	}
	
	/**
	 * 构造函数，传入文件，建立Xml文档(带命名空间的XML)
	 * @param file
	 * @param xmlNameSpace
	 * @param prefix
	 * @throws Exception
	 */
	public XmlDao(File file,String xmlNameSpace,String prefix) throws Exception {
		SAXReader reader = new SAXReader();
		reader.setValidation(false);
		reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
		Map map = new HashMap();
		map.put(prefix, xmlNameSpace);
		reader.getDocumentFactory().setXPathNamespaceURIs(map);
		this.doc = reader.read(file);
	}
	
	public XmlDao(Reader reader,String xmlNameSpace,String prefix) throws Exception {
		SAXReader read = new SAXReader();
		read.setValidation(false);
		read.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); 
		Map map = new HashMap();
		map.put(prefix, xmlNameSpace);
		read.getDocumentFactory().setXPathNamespaceURIs(map);
		this.doc = read.read(reader);
	}

	/**
	 * 构造函数，传入xml格式文本，建立Xml文档
	 * 
	 * @param file
	 * @throws DocumentException
	 */
	public XmlDao(String xmlContent) throws Exception{		
		this.doc = DocumentHelper.parseText(xmlContent);
		
	}

	/**
	 * 遍历Xml文档的所有节点和属性，转换成XmlNode对象
	 * 
	 * @return
	 */
	public XmlNode getAllInDocument() {
		Element root = doc.getRootElement();
		return getXmlNode(root);
	}
	
	/**
	 * 递推函数，遍历所有节点
	 * 
	 * @param element
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private XmlNode getXmlNode(Element element) {
		XmlNode xmlNode = new XmlNode();
		// 节点名、节点值
		xmlNode.setName(element.getName());
		xmlNode.setValue(element.getTextTrim());
		// 遍历属性
		Iterator<Attribute> attributeIterator = element.attributeIterator();
		while (attributeIterator.hasNext()) {
			Attribute attribute = (Attribute) attributeIterator.next();
			xmlNode.setAttribute(attribute.getName(), attribute.getValue());
		}
		// 遍历下级节点
		Iterator<Element> elementIterator = element.elementIterator();
		while (elementIterator.hasNext()) {
			Element subElement = (Element) elementIterator.next();
			xmlNode.setSubNode(getXmlNode(subElement));
		}
		return xmlNode;
	}
	
	/**
	 * 获取某一节点的XML
	 * @param xpath
	 * @return
	 */
	public String getPartXml(String xpath){
		StringBuffer tempXmlStr = new StringBuffer("");
		List <Node> list = this.doc.selectNodes(xpath);
		for(int i=0;i<list.size();i++){
			Node node = list.get(i);
			tempXmlStr.append(node.asXML());
		}
		return tempXmlStr.toString();
	}
	
	public String getDocumnetXml(){
		return this.doc.asXML();
	}
	/**
	 * 测试函数
	 * 
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
	
		
		File file = new File("D:\\workspace\\pas_db2\\WebRoot\\WEB-INF\\tld\\diy\\tiancomtag.tld");
		/*SAXReader reader = new SAXReader();
		reader.setValidation(false);
		reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
		Map map = new HashMap();
	    map.put("myXmlns","http://java.sun.com/xml/ns/j2ee");
		reader.getDocumentFactory().setXPathNamespaceURIs(map);
		Document doc = reader.read(file);*/
		XmlDao xml = new XmlDao(file,"http://java.sun.com/xml/ns/j2ee","myns");
		System.out.println(xml.getValue("/taglib/myns:tag[myns:name='text']/myns:tag-class"));
	}

	/**
	 * 说明：根据xpath获取属性或者节点集合
	 * 
	 * @param filename
	 * @param xpath
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public List<Node> getNodes(String xpath) {
		return doc.selectNodes(xpath);
	}

	/**
	 * 说明：根据xpath获取单一节点
	 * 
	 * @param filename
	 * @param xpath
	 * @return
	 * @throws Exception
	 */
	public Node getSingleNode(String xpath) {
		return doc.selectSingleNode(xpath);
	}

	/**
	 * 根据xpath获取XML文件的单个属性或者单个节点值
	 * 
	 * @param filename
	 * @param xpath
	 * @return
	 * @throws Exception
	 */
	public String getValue(String xpath) {
		String str;
		try{
			str = doc.selectSingleNode(xpath).getStringValue().trim();
		}catch(Exception e){
			str = "";
			//e.printStackTrace();
		}
		return str;
	}
	
	public String getValue(Node node,String xpath) {
		String str;
		try{
			str = node.selectSingleNode(xpath).getStringValue().trim();
		}catch(Exception e){
			str = "";
		}
		return str;
	}
	
	public OutputStream getOutputStream(){
		return null;
	}
	
	/**
	 * 根据XmlNode输出Xml文件流
	 * @param xmlNode
	 * @param out
	 * @throws Exception
	 */
	public static void exportXml(XmlNode xmlNode,Writer out) throws Exception {
		Document document = DocumentHelper.createDocument();
		Element root = document.addElement(xmlNode.getName());
		createElement(root,xmlNode);
        //用于格式化输出
        //OutputFormat format = OutputFormat.createPrettyPrint();
        //第1个参数为格式化输出缩排字符,此处为空格,第2个参数true为换行输出,false为单行输出
		//第3个参数为编码，输出为GBK码解决在windows下某些系统下打开含有中文xml乱码的情况
        OutputFormat format=new OutputFormat("\t",true,"GBK");
        XMLWriter xw = new XMLWriter(out,format);
        xw.write(document);
        xw.close();
	}
	/**
	 * 递推加截所有节点属性
	 * @param element
	 * @param Node
	 * @throws Exception
	 */
	private static void createElement(Element element,XmlNode node)throws Exception {
		//添加节点值
		if(node.getValue()!=null)
			element.setText(node.getValue());
		//添加节点属性
		List <String> attributeList = node.getAttributesName();
		if(attributeList!=null&&attributeList.size()>0){
			for(int i=0;i<attributeList.size();i++){
				String key = attributeList.get(i);
				element.addAttribute(key, node.getAttribute(key));
			}
		}
		
		//添加下级节点
		ArrayList <XmlNode> subNodeList = node.getSubNode();
		for(int i=0;i<subNodeList.size();i++){
			XmlNode subNode = subNodeList.get(i);
			Element sub = element.addElement(subNode.getName());
			createElement(sub,subNode);
		}
	}

}